package cn.zhqr.core.service;

import cn.zhqr.common.bean.response.ErrorCode;
import cn.zhqr.common.bean.response.OutResponse;
import cn.zhqr.common.config.GlobalConstants;
import cn.zhqr.common.util.str.StringUtils;
import cn.zhqr.common.util.validate.ParamCheck;
import cn.zhqr.common.utils.DateUtils;
import cn.zhqr.common.util.number.NumberUtils;
import cn.zhqr.common.util.number.SnowflakeIdWorker;
import cn.zhqr.core.bean.OrderRefundCheckResult;
import cn.zhqr.core.bean.PayNotify;
import cn.zhqr.core.bean.RefundNotify;
import cn.zhqr.core.utils.StockLock;
import com.jfinal.ext.plugin.tx.DbTx;
import com.jfinal.ext.plugin.tx.Tx;
import com.jfinal.plugin.activerecord.Record;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PayOrderService {
    public static final PayOrderService instance = new PayOrderService();
    public static final Logger logger = Logger.getLogger(UserOrderService.class);


    /**
     * 申请退款
     * @param orderNo
     * @param refundAmount
     * @param remark
     * @return
     */
    public OutResponse applyRefund(BigInteger orderNo, BigDecimal refundAmount, String remark){
        ParamCheck.isNotNull(orderNo,"订单号不能为空");
        ParamCheck.isNotNull(refundAmount,"退款金额不能为空");
        ParamCheck.check(refundAmount.compareTo(BigDecimal.ZERO)>0,"退款金额须大于0");

        PayOrder oriPayOrder = PayOrder.dao.findByOrderNo(orderNo);

//        if(oriPayOrder.getPayChannel() == GlobalConstants.PAY_CHANNEL_BAOFU_PAY){
//            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"该订单暂不支持退款");
//        }

        //检查是否可以退款
        OutResponse checkResult = checkRefund(oriPayOrder,refundAmount,null);
        if(!checkResult.isSuccess()){
            return checkResult;
        }

        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(1);
        BigInteger refundNo = BigInteger.valueOf(snowflakeIdWorker.nextId());


        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setRefundNo(refundNo);
        orderRefund.setOriOrderNo(oriPayOrder.getOrderNo());
        orderRefund.setUserId(oriPayOrder.getUserId());
        orderRefund.setStationId(oriPayOrder.getStationId());
        orderRefund.setAgentId(oriPayOrder.getAgentId());
        orderRefund.setCreateTime(new Date());
        orderRefund.setRefundStatus(OrderRefund.REFUND_STATUS_WAITING);
        orderRefund.setRefundAmount(refundAmount);
        orderRefund.setRemark(remark);
        orderRefund.save();

        return OutResponse.buildSuccess("退款申请已提交",null);
    }


    /**
     * 退款校验
     * @param oriPayOrder
     * @param refundAmount
     * @return
     */
    public OutResponse<List<OrderRefundCheckResult>> checkRefund(PayOrder oriPayOrder, BigDecimal refundAmount, OrderRefund orderRefund){
        ParamCheck.isNotNull(oriPayOrder,"原订单不存在");
        if(oriPayOrder == null){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"原订单不存在");
        }
        if(oriPayOrder.getStatus()!=PayOrder.STATUS_SUCCESS){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"该订单未支付成功，不可退款");
        }
        if(refundAmount.compareTo(oriPayOrder.getPayAmount())>0){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"退款金额不能超过订单实际支付金额");
        }

        BigDecimal remainingRefundableAmount = oriPayOrder.getPayAmount().subtract(oriPayOrder.getRefundAmount());//订单剩余可退金额
        BigDecimal refundingAmount = BigDecimal.ZERO;
        if(orderRefund != null){
            refundingAmount = OrderRefund.dao.sumRefundingAmountByOriOrderNoExceptRefundNo(oriPayOrder.getOrderNo(),orderRefund.getRefundNo());//减去正在退款中的金额
        }else{
            refundingAmount = OrderRefund.dao.sumRefundingAmountByOriOrderNo(oriPayOrder.getOrderNo());//减去正在退款中的金额
        }

        remainingRefundableAmount = remainingRefundableAmount.subtract(refundingAmount);//实际可退金额

        if(refundAmount.compareTo(remainingRefundableAmount) > 0){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"该订单剩余可退款金额为"+remainingRefundableAmount+"元");
        }


        User member = User.dao.findByUserId(oriPayOrder.getUserId());
        if(member == null){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"订单用户不存在");
        }

        List<OrderRefundCheckResult> orderRefundCheckResultList = new ArrayList<>();
//        if(oriPayOrder.getSplitAmount().compareTo(BigDecimal.ZERO) > 0){
            OrderSplit orderSplit = OrderSplit.dao.findByOriOrderNo(oriPayOrder.getOrderNo());
            if(orderSplit != null){
                List<Record> recordList = OrderSplitLog.dao.groupStatUnsettledBySplitId(orderSplit.getId());
                BigDecimal totalSplitAmount = BigDecimal.ZERO;
                for(Record record : recordList){
                    totalSplitAmount = totalSplitAmount.add(record.getBigDecimal("total_amount")).add(record.getBigDecimal("total_fee"));
                }

                for(Record record : recordList){
                    Long toAgentId = record.getLong("to_agent_id");
                    BigDecimal totalAmount = record.getBigDecimal("total_amount");
                    BigDecimal totalFee = record.getBigDecimal("total_fee");

                    //计算需要分摊的退款额
                    BigDecimal splitRefundAmount = refundAmount.multiply(totalAmount.add(totalFee)).divide(totalSplitAmount,2, GlobalConstants.DEFAULT_ROUNDING_MODE);
                    //计算未结算金额
                    BigDecimal unsettledAmount = OrderSplitLog.dao.sumUnsettledByAgentId(toAgentId);
                    //计算分摊的退款额和未结算金额的差额
                    BigDecimal diffAmount = splitRefundAmount.subtract(unsettledAmount);

                    //未结算金额不足以抵扣退款金额，则需通过余额抵扣
                    if(diffAmount.compareTo(BigDecimal.ZERO) > 0){
                        AgentWallet agentWallet = AgentWallet.dao.findByAgentId(toAgentId);
                        if(agentWallet == null){
                            return OutResponse.buildError(ErrorCode.ACCOUNT_NOT_REGISTER,"账户未开通："+toAgentId);
                        }

                        //可用金额 = 余额 - 冻结金额
                        BigDecimal availableBalance = agentWallet.getBalance().subtract(agentWallet.getFrozenBalance());

                        if(availableBalance.compareTo(diffAmount) < 0){
                            String agentName = Agent.dao.findNameById(toAgentId);
                            return OutResponse.buildError(ErrorCode.BALANCE_NOT_ENOUGH,"分账人"+agentName+"账户余额不足，无法退款");
                        }

                        orderRefundCheckResultList.add(new OrderRefundCheckResult(toAgentId,diffAmount));
                    }
                }
            }
//        }

        return OutResponse.buildSuccess(orderRefundCheckResultList);
    }


    /**
     * 处理支付结果通知
     * @param payNotify
     * @return
     */
    public OutResponse processPayNotify(PayNotify payNotify){
        OutResponse[] result = new OutResponse[1];
        DbTx.execute(new Tx() {
            @Override
            public void sql() {
                //上锁，防止重复修改
                PayOrder payOrder = PayOrder.dao.findAndLockByOrderNo(payNotify.getOrderNo());
                if(payOrder==null){
                    result[0] = OutResponse.buildError(ErrorCode.INVALID_PARAM,"订单不存在 order_no："+payNotify.getOrderNo());
                    return;
                }
                if(payOrder.getStatus() == PayOrder.STATUS_SUCCESS){
                    result[0] = OutResponse.buildSuccess("订单已完成",null);
                    return;
                }

                if(StringUtils.isBlank(payNotify.getPayNo()) || !"SUCCESS".equalsIgnoreCase(payNotify.getOrderStatus())){
                    payOrder.setErrMsg(payNotify.getResCode()+" "+payNotify.getResMsg());
                    payOrder.setStatus(payOrder.STATUS_FAILED);
                    payOrder.update();
                    logger.error(payOrder.getUserId()+" 订单："+payOrder.getOrderNo()+" 支付失败："+payNotify.getResCode()+"-"+payNotify.getResMsg());
                    result[0] = OutResponse.buildError(ErrorCode.PAY_FAILED,"支付失败："+payNotify.getResMsg());
                    return;
                }

                OutResponse response = OutResponse.buildError(ErrorCode.SQL_ERROR,"购买失败");
                if(payOrder.getGoodsType()== Goods.TYPE_WASH_CARD){
                    //购买洗车卡
                    response = UserCardService.instance.getCardFromBuy(payOrder);
                }

                if(!response.isSuccess()){
                    result[0] = OutResponse.buildError(ErrorCode.PAY_FAILED,"订单处理失败："+payNotify.getResMsg());
                    return;
                }

                StockLock.unlock(StockLock.Stock.WASH_CARD,1);

                payOrder.setPayNo(payNotify.getPayNo());
                payOrder.setStatus(payOrder.STATUS_SUCCESS);
                payOrder.setPayTime(new Date());
                payOrder.setPayAmount(NumberUtils.decimal(payNotify.getOrderAmount()));
                payOrder.setUpdateTime(payOrder.getPayTime());
                payOrder.update();


                //添加订单分账任务，通过定时任务异步执行
                OrderSplitService.instance.addOrderSplitTask(payOrder);

                //后续处理
                processPaySuccess(payOrder);

                result[0] = OutResponse.buildSuccess();
            }

            @Override
            public void error(Exception e) {
                logger.error("process pay notify transaction error:",e);
                result[0] = OutResponse.buildError(ErrorCode.SQL_ERROR,"process pay notify transaction error:"+e.getMessage());
            }
        });

        return result[0];
    }

    /**
     * 处理支付成功后续逻辑
     * @param payOrder
     */
    private void processPaySuccess(PayOrder payOrder){
        try{
            rewardShareUser(payOrder);
        }catch (Exception e){
            logger.error("processPaySuccess error:",e);
        }
    }

    private void rewardShareUser(PayOrder payOrder){
        try{
            ShareReceiveLog log = ShareReceiveLog.dao.findByUserIdAndStationIdAndStatus(payOrder.getUserId(), payOrder.getStationId(),ShareReceiveLog.STATUS_NORMAL);
            if(log == null) return;

            ShareActivity activity = ShareActivity.dao.findById(log.getActivityId());
            if(activity==null) return;
            Date now = new Date();
            if(DateUtils.diffDays(now,log.getCreateTime())> activity.getCompleteDaysLimit()) return;

            if(activity.getShareRewardNum()<=0) return;

            if(DateUtils.diffMilliseconds(now,activity.getStartTime())<0) return;
            if(DateUtils.diffMilliseconds(now,activity.getEndTime())>0) return;

            WashCard washCard = WashCard.dao.findById(activity.getShareRewardId());
            if(washCard==null) return;

            if(!CardService.instance.checkStock(washCard.getId())) return;

            //判断规则，是否可领
            long shareCount = ShareReceiveLog.dao.countByShareUserIdAndStatus(log.getShareUserid(), ShareReceiveLog.STATUS_COMPLETED);
            if(shareCount >= activity.getShareMaxTimes()) return;
            //领取
            UserCardService.instance.getCardFromActivity(log.getShareUserid(),activity.getShareRewardId(), activity.getId());

            log.setStatus(ShareReceiveLog.STATUS_COMPLETED);
            log.update();
        }catch (Exception e){
            logger.error("rewardShareUser error:",e);
        }
    }


    public OutResponse processRefundNotify(RefundNotify refundNotify){
        PayOrder payOrder = PayOrder.dao.findAndLockByOrderNo(refundNotify.getOriOrderNo());
        if(payOrder == null){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"原始订单不存在");
        }

        OrderRefund orderRefund = OrderRefund.dao.findAndLockByRefundNo(refundNotify.getRefundNo());

        if(orderRefund != null && orderRefund.getRefundStatus()==OrderRefund.REFUND_STATUS_SUCCESS){
            return OutResponse.buildSuccess("订单已经处理过了",null);
        }
        User user = User.dao.findByUserId(payOrder.getUserId());
        if(user == null){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"该用户不存在");
        }

        if(orderRefund == null){
            orderRefund = new OrderRefund();
            orderRefund.setUserId(payOrder.getUserId());
            orderRefund.setAgentId(payOrder.getAgentId());
            orderRefund.setStationId(payOrder.getStationId());
            orderRefund.setRefundAmount(refundNotify.getOrderAmount());
            orderRefund.setRefundNo(new BigInteger(refundNotify.getRefundNo()));
            orderRefund.setOriOrderNo(new BigInteger(refundNotify.getOriOrderNo()));
            orderRefund.setCreateTime(new Date());
            orderRefund.setRefundStatus(OrderRefund.REFUND_STATUS_PROCESSING);
        }

        if("SUCCESS".equals(refundNotify.getOrderStatus())){
            orderRefund.setPayTime(new Date());
            orderRefund.setRefundStatus(OrderRefund.REFUND_STATUS_SUCCESS);
            orderRefund.setPayTime(new Date());
            orderRefund.setMsg("退款成功");
            orderRefund.update();

            PayOrder.dao.increaseRefundAmount(payOrder.getOrderNo(),refundNotify.getOrderAmount());

            UserWashCard userWashCard = UserWashCard.dao.findByPayOrderNo(payOrder.getOrderNo());
            if(userWashCard != null){
                userWashCard.setStatus(UserWashCard.STATUS_REFUNDED);
                userWashCard.setExpireTime(new Date());
                userWashCard.update();
            }

            AgentFrozenTradeService.instance.unfreeze(orderRefund.getRefundNo());

            OrderSplit orderRefundSplit = new OrderSplit();
            orderRefundSplit.setType(OrderSplit.TYPE_REFUND);
            orderRefundSplit.setUserId(payOrder.getUserId());
            orderRefundSplit.setStationId(payOrder.getStationId());
            orderRefundSplit.setAgentId(payOrder.getAgentId());
            orderRefundSplit.setAmount(orderRefund.getRefundAmount().min(payOrder.getSplitAmount()).negate());
            orderRefundSplit.setCreateTime(new Date());
            orderRefundSplit.setStatus(OrderSplit.STATUS_WAITING);
            orderRefundSplit.setOriOrderNo(payOrder.getOrderNo());
            orderRefundSplit.setRelationNo(orderRefund.getRefundNo());
            orderRefundSplit.save();

            return OutResponse.buildSuccess("退款成功",null);
        }else if("FAIL".equals(refundNotify.getOrderStatus())){
            AgentFrozenTradeService.instance.unfreeze(orderRefund.getRefundNo());

            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"退款失败",null);
        }else{
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"交易进行中",null);
        }
    }
}
